package com.chatplus.application.common.util;


import com.chatplus.application.common.enumeration.PhoneNumberSection;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;

@SuppressWarnings({"unused", "WeakerAccess"})
public abstract class CommonUtils {
    private CommonUtils() {
    }
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    private static final String HashAlgorithm = "RipeMD160";
    private static final String SHA256 = "SHA-256";

    @SuppressWarnings("WeakerAccess")
    public static final Pattern CellPhonePattern = Pattern.compile("^(\\+\\d{2,4}-?)?(1[^012]\\d{9})$");

    private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    private static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<>();

    static {
        wrapperPrimitiveMap.put(Boolean.class, boolean.class);
        wrapperPrimitiveMap.put(Byte.class, byte.class);
        wrapperPrimitiveMap.put(Character.class, char.class);
        wrapperPrimitiveMap.put(Double.class, double.class);
        wrapperPrimitiveMap.put(Float.class, float.class);
        wrapperPrimitiveMap.put(Integer.class, int.class);
        wrapperPrimitiveMap.put(Long.class, long.class);
        wrapperPrimitiveMap.put(Short.class, short.class);
    }

    public static String hex(byte[] data) {
        char[] result = new char[data.length * 2];
        int c = 0;
        for (byte b : data) {
            result[c++] = HEX_DIGITS[(b >> 4) & 0xf];
            result[c++] = HEX_DIGITS[b & 0xf];
        }
        return new String(result);
    }

    public static byte[] hash(byte[] bytes) {
        try {
            return MessageDigest.getInstance(HashAlgorithm).digest(bytes);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    public static String hexHash(byte[] bytes) {
        return hex(hash(bytes));
    }

    public static byte[] sha256(byte[] input) {
        try {
            return MessageDigest.getInstance(SHA256).digest(input);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    public static boolean isPrimitiveWrapper(final Class<?> type) {
        return wrapperPrimitiveMap.containsKey(type);
    }

    public static boolean isPrimitiveOrWrapper(final Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isPrimitive() || isPrimitiveWrapper(type);
    }

    public static boolean equals(CharSequence source, CharSequence target) {
        if (source == target) {
            return true;
        }

        if (source == null || target == null || source.length() != target.length()) {
            return false;
        }

        if (source instanceof String && target instanceof String && !source.equals(target)) {
            return false;
        }

        return IntStream.range(0, source.length()).noneMatch(i -> source.charAt(i) != target.charAt(i));
    }

    @SuppressWarnings("rawtypes")
    public static boolean isEmpty(Object object) {
        return null == object
            || (object instanceof String && ((String) object).isEmpty())
            || (object instanceof Collection && ((Collection) object).isEmpty())
            || (object instanceof Object[] && 0 == ((Object[]) object).length);
    }

    public static boolean notEmpty(Object object) {
        return !isEmpty(object);
    }

    /**
     * https://zh.wikipedia.org/wiki/%E4%B8%AD%E5%9B%BD%E5%86%85%E5%9C%B0%E7%A7%BB%E5%8A%A8%E7%BB%88%E7%AB%AF%E9%80%9A%E8%AE%AF%E5%8F%B7%E6%AE%B5#%E5%8F%B7%E7%A0%81%E5%88%86%E9%85%8D
     */
    public static PhoneNumberSection detectPhoneNumberSection(String phone) {
        if (null == phone) {
            return null;
        }

        Matcher matcher = CellPhonePattern.matcher(phone);
        if (!matcher.matches()) {
            return null;
        }

        phone = matcher.group(2);

        String leading4 = phone.substring(0, 4);
        switch (leading4) {
            case "1349":
            case "1410":
            case "1700":
            case "1701":
            case "1702":
            case "1740":
            case "1741":
            case "1742":
            case "1743":
            case "1744":
            case "1745":
                return PhoneNumberSection.ChinaTelecom;
            case "1340":
            case "1341":
            case "1342":
            case "1343":
            case "1344":
            case "1345":
            case "1346":
            case "1347":
            case "1348":
            case "1440":
            case "1703":
            case "1705":
            case "1706":
                return PhoneNumberSection.ChinaMobile;
            case "1400":
            case "1704":
            case "1707":
            case "1708":
            case "1709":
                return PhoneNumberSection.ChinaUnicom;
            case "1799":
                return PhoneNumberSection.ChinaTransportTelecommunication;
            default:
                break;
        }

        String leading3 = phone.substring(0, 3);
        switch (leading3) {
            case "133":
            case "149":
            case "153":
            case "162":
            case "173":
            case "177":
            case "180":
            case "181":
            case "189":
            case "190":
            case "191":
            case "193":
            case "199":
                return PhoneNumberSection.ChinaTelecom;
            case "135":
            case "136":
            case "137":
            case "138":
            case "139":
            case "147":
            case "148":
            case "150":
            case "151":
            case "152":
            case "157":
            case "158":
            case "159":
            case "165":
            case "172":
            case "178":
            case "182":
            case "183":
            case "184":
            case "187":
            case "188":
            case "195":
            case "197":
            case "198":
                return PhoneNumberSection.ChinaMobile;
            case "130":
            case "131":
            case "132":
            case "145":
            case "146":
            case "155":
            case "156":
            case "166":
            case "167":
            case "171":
            case "175":
            case "176":
            case "185":
            case "186":
            case "196":
                return PhoneNumberSection.ChinaUnicom;
            case "192":
                return PhoneNumberSection.ChinaBroadcastingNetwork;
            default:
                return PhoneNumberSection.Unknown;
        }
    }

    public static String replaceDigital(String value, String replaceParam) {
        Pattern p = Pattern.compile("[\\d]");
        Matcher matcher = p.matcher(value);
        return matcher.replaceAll(replaceParam);
    }

}
